/*
 * Copyright (C) 2010, Funcom AS, All Rights Reserved
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *  @authors
 *  Svein Gunnar Larsen <sveingunnarlarsen@gmail.com>
 *  Erik Thune Lund <culex.eriklund@gmail.com>
 *  Michel Krohn-Dale <kronicz@gmail.com>
 */

package com.funcom.peeler.properties;

import com.funcom.peeler.PeelStyleSheet;
import com.funcom.peeler.UpdateCont;
import com.funcom.peeler.WorkBench;
import com.funcom.peeler.action.Change;
import com.funcom.peeler.action.LocaleTextChange;
import com.funcom.peeler.action.MultiChange;
import com.funcom.peeler.action.TextChange;
import com.funcom.peeler.adapter.KeyAndMouseAdapter;
import com.funcom.peeler.peelable.PeelComponent;
import com.funcom.peeler.peelable.PeelLabel;
import com.funcom.peeler.peelable.PeelTextComponent;
import com.funcom.peeler.symbol.Symbol;
import com.funcom.peeler.tool.Settings;
import com.funcom.peeler.utils.ColorPicker;
import com.funcom.peeler.utils.NumberErrorMessage;
import com.jme.renderer.ColorRGBA;
import com.jmex.bui.BLabel;
import com.jmex.bui.BTextComponent;
import com.jmex.bui.enumeratedConstants.HorizontalAlignment;
import com.jmex.bui.enumeratedConstants.VerticalAlignment;
import com.jmex.bui.util.Insets;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

public class TextSetting extends UpdateableProperties {

    JTextField[] padding;

    public static final int PADDING_LEFT = 0;
    public static final int PADDING_RIGHT = 1;
    public static final int PADDING_TOP = 2;
    public static final int PADDING_BOTTOM = 3;

    public static final int ALIGN_LEFT = 0;
    public static final int ALIGN_CENTER = 1;
    public static final int ALIGN_RIGHT = 2;
    public static final int ALIGN_BOTTOM = 3;
    public static final int ALIGN_VER_CENTER = 4;
    public static final int ALIGN_TOP = 5;
    public static final int ALIGNMENT_LENGTH = 6;

    JRadioButton[] alignmentButtons = new JRadioButton[ ALIGNMENT_LENGTH ];

    JTextField setText;
    JPanel pnlColor;

    JTextField localizedText;
    JComboBox localeChooser;

    private ResourceBundle localization;
    private Locale locale;

    String compText;
    Insets compInsets;

    Color defaultColor = new Color(204, 204, 204);

    ColorRGBA colorRGBA;

    public TextSetting(JTextField setText,
                       JRadioButton[] alignment,
                       JTextField[] padding,
                       JPanel pnlColor,
                       JTextField localizedText,
                       JComboBox localeChooser) {

        this.alignmentButtons = alignment;
        this.setText = setText;
        this.padding = padding;
        this.pnlColor = pnlColor;

        this.pnlColor.setBackground(defaultColor);
        this.pnlColor.setBorder(BorderFactory.createEtchedBorder());

        this.localizedText = localizedText;
        this.localeChooser = localeChooser;

        initListeners();
    }

    public void update() {

        setText.setText(compText);

        padding[PADDING_LEFT].setText(Integer.toString(compInsets.left));
        padding[PADDING_RIGHT].setText(Integer.toString(compInsets.right));
        padding[PADDING_TOP].setText(Integer.toString(compInsets.top));
        padding[PADDING_BOTTOM].setText(Integer.toString(compInsets.bottom));

        fields_cleared = false;
    }

    public void needUpdate( WorkBench workBench,
                            Set<PeelComponent> allComp,
                            Set<PeelComponent> selectedComps,
                            PeelComponent main_selected,
                            PropertiesFrame thisFrame ) {


        if (main_selected == null) {
            selectedComp = null;
            if (!fields_cleared) {
                clear();
                return;
            } else {
                return;
            }
        }

        if (selectedComp != main_selected) {
            selectedComp = main_selected;
            String styleClass = selectedComp.getComponent().getStyleClass();
            PeelStyleSheet stylesheet = selectedComp.getStyleSheet();

            if (stylesheet == null) return;

            if (selectedComp instanceof PeelLabel) {
                compText = ((BLabel) selectedComp.getComponent()).getText();
                compInsets = selectedComp.getComponent().getInsets();

                String align = String.valueOf(stylesheet.properties.get(styleClass).properties.get(Symbol.StyleProperty.text_align)).toLowerCase();
                String vertAlign = String.valueOf(stylesheet.properties.get(styleClass).properties.get(Symbol.StyleProperty.vertical_align)).toLowerCase();
                String localizationKey = String.valueOf(selectedComp.getComponent().getProperty(Symbol.Attr.locale_text));

                if(localizationKey.equals("null")){
                    localizedText.setText("");
                }else localizedText.setText(localizationKey);

                if(!align.equals("null")){
                    if(align.equals("left")) alignmentButtons[ALIGN_LEFT].setSelected(true);
                    else if(align.equals("right")) alignmentButtons[ALIGN_RIGHT].setSelected(true);
                    else if(align.equals("center")) alignmentButtons[ALIGN_CENTER].setSelected(true);
                }

                if(!vertAlign.equals("null")){
                    if(vertAlign.equals("top")) alignmentButtons[ALIGN_TOP].setSelected(true);
                    else if(vertAlign.equals("center")) alignmentButtons[ALIGN_VER_CENTER].setSelected(true);
                    else if(vertAlign.equals("bottom")) alignmentButtons[ALIGN_BOTTOM].setSelected(true);
                }

                ColorRGBA background = (ColorRGBA) stylesheet.properties.get(styleClass).properties.get(Symbol.StyleProperty.color);

                if( background == null) {
                    pnlColor.setBackground(defaultColor);
                    wantUpdate = true;
                    return;
                }

                Color current_color = new Color(background.r, background.g, background.b);
                if(!pnlColor.getBackground().equals(current_color)){
                    pnlColor.setBackground(current_color);
                }

                wantUpdate = true;
            } else {
                if ( fields_cleared )
                    clear();
            }
        }
        else if ( selectedComp == main_selected){
                if ( selectedComp instanceof PeelLabel ) {
                   if( !((BLabel)selectedComp.getComponent()).getText().equals( compText ))  {
                    selectedComp = null;
                   }
                }
        }
    }

    public void applyChange( PeelComponent component, PropertiesFrame updater ) {

        switch (change) {
            case PADDING: {
                try {
                    int left   = Integer.parseInt(padding[PADDING_LEFT].getText());
                    int right  = Integer.parseInt(padding[PADDING_RIGHT].getText());
                    int top    = Integer.parseInt(padding[PADDING_TOP].getText());
                    int bottom = Integer.parseInt(padding[PADDING_BOTTOM].getText());

                    Insets newInsets = new Insets(left, top, right, bottom);

                    updater.applyToSelectedStates(component, newInsets);

                    } catch (NumberFormatException e) {
                        SwingUtilities.invokeLater( new Runnable() {
                            public void run() {
                                NumberErrorMessage.numberError("Not a valid number");
                            }
                        });
                    padding[PADDING_LEFT].setText(String.valueOf(component.getComponent().getInsets().left));
                    padding[PADDING_RIGHT].setText(String.valueOf(component.getComponent().getInsets().right));
                    padding[PADDING_BOTTOM].setText(String.valueOf(component.getComponent().getInsets().bottom));
                    padding[PADDING_TOP].setText(String.valueOf(component.getComponent().getInsets().top));
                    }
                break;
            }
            case TEXT: {
                if (component instanceof PeelTextComponent) {
                    Collection< Change > changes = new ArrayList< Change >();
                    changes.add( new TextChange( component, ((BLabel)component.getComponent()).getText(), setText.getText() ) );
                    changes.add( new LocaleTextChange( component, (String)component.getComponent().getProperty( Symbol.Attr.locale_text ), localizedText.getText() ) );
                    UpdateCont.get().getFocusedWorkBench().pushChange( new MultiChange( changes ) );
                    component.getComponent().setProperty( Symbol.Attr.locale_text, localizedText.getText() );
                    (( BTextComponent )component.getComponent()).setText(setText.getText());
                }

                break;
            }
            case TEXT_COLOR: {

                ColorRGBA newColor = new ColorRGBA(colorRGBA);
                updater.applyToSelectedStates(component, newColor);

                break;
            }
            case ALIGNMENT: {

                if (alignmentButtons[ALIGN_LEFT].isSelected()) {
                    updater.applyToSelectedStates(component, HorizontalAlignment.LEFT);
                }
                else if (alignmentButtons[ALIGN_CENTER].isSelected()) {
                    updater.applyToSelectedStates(component, HorizontalAlignment.CENTER);
                }
                else if (alignmentButtons[ALIGN_RIGHT].isSelected()) {
                    updater.applyToSelectedStates(component, HorizontalAlignment.RIGHT);
                }
                if (alignmentButtons[ALIGN_TOP].isSelected()) {
                    updater.applyToSelectedStates(component, VerticalAlignment.TOP);
                }
                else if (alignmentButtons[ALIGN_VER_CENTER].isSelected()) {
                    updater.applyToSelectedStates(component, VerticalAlignment.CENTER);
                }
                else if (alignmentButtons[ALIGN_BOTTOM].isSelected()) {
                    updater.applyToSelectedStates(component, VerticalAlignment.BOTTOM);
                }
                break;
            }
        }
    }

    public void clear() {

        setText.setText("");

        padding[PADDING_LEFT].setText("");
        padding[PADDING_RIGHT].setText("");
        padding[PADDING_TOP].setText("");
        padding[PADDING_BOTTOM].setText("");

        alignmentButtons[ALIGN_VER_CENTER].setSelected(true);
        alignmentButtons[ALIGN_CENTER].setSelected(true);

        localizedText.setText("");

        pnlColor.setBackground(defaultColor);
        fields_cleared = true;
    }

    protected void initListeners() {

        localeChooser.addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                handleLocalization();
                change = ChangeProp.TEXT;
            }
        });

        localizedText.addKeyListener(new KeyAndMouseAdapter(){
            public void keyPressed(KeyEvent e){
                if( e.getKeyCode() == e.VK_Z && e.isControlDown() ){
                    localizedText.setText("");
                    selectedComp.getComponent().setProperty(Symbol.Attr.locale_text, null);
                    setText.setText(((BTextComponent)selectedComp.getComponent()).getText());
                    return;
                }
                if(e.getKeyCode() == KeyEvent.VK_ENTER){
                    handleLocalization();
                    localizedText.transferFocus();
                    change = ChangeProp.TEXT;
                }
            }
        });

        setText.addKeyListener(new KeyAndMouseAdapter() {
            public void keyPressed(KeyEvent e) {

                if ( e.getKeyCode() == e.VK_Z && e.isControlDown() ) {
                    try{
                        setText.setText(((BTextComponent)selectedComp.getComponent()).getText());
                        return;
                    }catch(NullPointerException npe){
                        return;
                    }
                }

                if ( e.getKeyCode() == e.VK_SHIFT ) return;

                change = ChangeProp.TEXT;
            }
        });

        ActionListener alignmentList = new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                change = ChangeProp.ALIGNMENT;
            }
        };
        PaddingListener listener = new PaddingListener();

        for (JRadioButton aRadioButton : alignmentButtons) {
            aRadioButton.addActionListener(alignmentList);
        }
        for(JTextField aTextField : padding) {
            aTextField.addKeyListener(listener);
            aTextField.addFocusListener(listener);
        }

        pnlColor.addMouseListener(new KeyAndMouseAdapter() {
            public void mouseClicked(MouseEvent evt) {
                colorRGBA = ColorPicker.selectColor(pnlColor, "Set text color");
                if (colorRGBA != null) {
                    change = ChangeProp.TEXT_COLOR;
                }
            }
        });
    }
    private class PaddingListener extends KeyAndMouseAdapter {
        public void keyPressed(KeyEvent e) {
            if(e.getKeyCode() == KeyEvent.VK_ENTER){
                if(e.getSource() == padding[0]) {
                    change = ChangeProp.PADDING;
                }else if(e.getSource() == padding[1]){
                    change = ChangeProp.PADDING;
                }else if(e.getSource() == padding[2]){
                    change = ChangeProp.PADDING;
                }else if(e.getSource() == padding[3]){
                    change = ChangeProp.PADDING;
                }
            }
        }

        public void focusLost(FocusEvent e){
            if(e.getSource() == padding[0]) {
                change = ChangeProp.PADDING;
            }else if(e.getSource() == padding[1]){
                change = ChangeProp.PADDING;
            }else if(e.getSource() == padding[2]){
                change = ChangeProp.PADDING;
            }else if(e.getSource() == padding[3]){
                change = ChangeProp.PADDING;
            }
        }
    }

    private void handleLocalization() {
        Settings settings = UpdateCont.get().getFocusedWorkBench().getBui().getPeelRoot().getSettings();
        locale = new Locale(localeChooser.getSelectedItem().toString());
        String bundle = settings.getBasePath() + settings.getLocalizerPath() + "_" + locale + ".properties";

        try {
            InputStream is = new FileInputStream( bundle );
            localization = new PropertyResourceBundle( is );

            try {
                    setText.setText(localization.getString(localizedText.getText()));
            }
            catch (MissingResourceException mre) {
                JOptionPane.showMessageDialog(null, "Key cannot be found");
            }
        }
        catch (MissingResourceException mre) {
                JOptionPane.showMessageDialog(null, "Please choose a valid resource bundle in settings ", "Missing resource bundle" , JOptionPane.WARNING_MESSAGE);
        }
        catch ( FileNotFoundException e ) {
            JOptionPane.showMessageDialog( null,"Selected resource file not found, select a new locale or a new bundle.", "File not found", JOptionPane.WARNING_MESSAGE );
        }
        catch ( IOException e ) {
            e.printStackTrace();
        }
        catch (NullPointerException npe) {
            JOptionPane.showMessageDialog(null, "Please choose a valid resource bundle in settings", "Missing resource bundle", JOptionPane.WARNING_MESSAGE);
        }
    }
}
